/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.yy.bugzillahelp.action.download;

import com.yy.bugzillahelp.MainFrame;
import com.yy.bugzillahelp.data.BugCommentData;
import com.yy.bugzillahelp.data.BugDetailData;
import com.yy.bugzillahelp.data.server.ServerData;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * 这个类用来从bugzilla服务器上抓取bug信息
 *
 * @author hualun-alan
 */
public class BugCrawlAction {

    public static String doRequest(String url, boolean isXml) {
        StringBuilder sb = new StringBuilder();
        try {
            URL jspURL = new URL(url);
            System.out.println(url);
            URLConnection urlCon = (URLConnection) jspURL.openConnection();
            urlCon.setUseCaches(false);
            InputStream inputStream = urlCon.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
            String line = br.readLine();
            while (line != null) {
                if ((!isXml || !line.contains("DOCTYPE")) && !line.trim().isEmpty()) {
                    sb.append(line).append("\n");
                }
                line = br.readLine();
            }
            br.close();
            inputStream.close();
        } catch (IOException ex) {
            Logger.getLogger(BugCrawlAction.class.getName()).log(Level.SEVERE, null, ex);
        }

        return sb.toString();
    }

    public static boolean checkUrlAvilable(String url) {
        try {
            URL jspURL = new URL(url);
            URLConnection urlCon = (URLConnection) jspURL.openConnection();
            urlCon.setUseCaches(false);
            InputStream inputStream = urlCon.getInputStream();
            inputStream.close();
        } catch (IOException ex) {
            Logger.getLogger(BugCrawlAction.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }

        return true;
    }

    public static String getIdsByTime(ServerData connectData, String time) {
        String html = doRequest(connectData.getServerUrl() + "/buglist.cgi?chfieldto=Now&query_format=advanced&chfieldfrom=" + time, false);
        return parseIds(html);
    }

    public static String getAllIds(ServerData connectData) {
        String html = doRequest(connectData.getServerUrl() + "/buglist.cgi?query_format=specific&order=relevance+desc&bug_status=__all__&product=&content=", false);
        return parseIds(html);
    }

    public static String getXMLById(ServerData connectData, String id) {
        return doRequest(connectData.getServerUrl() + "/show_bug.cgi?ctype=xml&id=" + id, true);
    }

    public static String getXMLByIdWithoutAttachment(ServerData connectData, String id) {
        return doRequest(connectData.getServerUrl() + "/show_bug.cgi?ctype=xml&excludefield=attachmentdata&id=" + id, true);
    }

    public static String parseIds(String html) {
        //以下代码是从html中的以下这段代码中解析出id
        //1  <form method="post" action="show_bug.cgi">
        //2  <input type="hidden" name="ctype" value="xml">
        //3  <input type="hidden" name="id" value="1250">
        //4  <input type="hidden" name="id" value="1446">
        //5  <input type="hidden" name="id" value="1477">
        //6  <input type="hidden" name="id" value="1590">
        //7  <input type="hidden" name="id" value="1591">
        //8  <input type="hidden" name="id" value="1592">
        //9  <input type="hidden" name="id" value="1594">
        //10 <input type="hidden" name="id" value="1601">
        //11 <input type="hidden" name="id" value="1603">
        //12 <input type="hidden" name="id" value="1604">
        //13 <input type="hidden" name="id" value="1605">
        //14 <input type="hidden" name="id" value="1606">
        //15 <input type="hidden" name="id" value="1607">
        //16 <input type="hidden" name="id" value="1608">
        //17 <input type="hidden" name="excludefield" value="attachmentdata">
        //18 <input type="submit" value="XML" id="xml">
        //19 </form>


        //首先，从整个html文档中检索到第@2行的位置，并移除前面的所以内容，包括第一行
        int idx1 = html.indexOf("<input type=\"hidden\" name=\"ctype\" value=\"xml\">");
        if (idx1 < 0) {
            //当没有找到第@2行时，表示这个时间段内没有id更新
            return "";
        }
        html = html.substring(idx1 + 52);

        //其次，从剩下的文档中见到到第@17行的位置，并移除其后面的内容
        int idx2 = html.indexOf("<input type=\"hidden\" name=\"excludefield\" value=\"attachmentdata\">");
        html = html.substring(0, idx2);

        //此时，html中只剩下了<input type="hidden" name="id" value="1250">这样的多行内容

        //然后，移除html中的所有换行符空格等影响到解析的特殊字符
        html = html.replace(" ", "").replace("\n", "").replace("\r", "");

        //最后，移除<input type="hidden" name="id" value="1250">中value内容前面的字符，同时将后面的字符替换为逗号
        html = html.replaceAll("<inputtype=\"hidden\"name=\"id\"value=\"", "").replaceAll("\">", ",");

        //得到如下结果：1607,1603,1605,1608,1606,1477,1592,1594,1604,1250,1601,1446,1591,1590,

        return html;
    }

    public static ArrayList<BugDetailData> parseXML(String xml) {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(new ByteArrayInputStream(xml.getBytes("UTF-8")));
            Element root = document.getDocumentElement();
            return parseNode(root);
        } catch (SAXException ex) {
            Logger.getLogger(BugCrawlAction.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(BugCrawlAction.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(BugCrawlAction.class.getName()).log(Level.SEVERE, null, ex);
        }

        return new ArrayList<BugDetailData>();
    }

    private static ArrayList<BugDetailData> parseNode(Element root) {
        ArrayList<BugDetailData> detailDatas = new ArrayList<BugDetailData>();

        NodeList childNodes = root.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);

            if (item.getNodeName().equals("bug")) {
                BugDetailData data = new BugDetailData();
                rollBugDetail(item.getChildNodes(), data);
                detailDatas.add(data);
            }
        }

        return detailDatas;
    }

    private static void rollBugDetail(NodeList childNodes, BugDetailData bugDetailsData) {
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            Node parentNode = item.getParentNode();
            if (parentNode.getNodeName().equals("bug_id")) {
                bugDetailsData.setBugId(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("creation_ts")) {
                bugDetailsData.setCreateTime(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("short_desc")) {
                bugDetailsData.setShortDesc(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("delta_ts")) {
                bugDetailsData.setModifyTime(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("product")) {
                bugDetailsData.setProduct(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("component")) {
                bugDetailsData.setComponent(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("version")) {
                bugDetailsData.setVersion(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("bug_status")) {
                bugDetailsData.setStatus(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("resolution")) {
                bugDetailsData.setResolution(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("priority")) {
                bugDetailsData.setPriority(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("bug_severity")) {
                bugDetailsData.setSeverity(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("reporter")) {
                bugDetailsData.setReporter(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("assigned_to")) {
                bugDetailsData.setAssignedTo(item.getNodeValue());
            }

            if (item.getNodeName().equals("long_desc")) {
                BugCommentData longDescData = new BugCommentData();
                longDescData.setBugId(bugDetailsData.getBugId());
                bugDetailsData.addDescData(longDescData);
                rollBugLongDesc(item.getChildNodes(), longDescData);
            } else {
                rollBugDetail(item.getChildNodes(), bugDetailsData);
            }
        }
    }

    private static void rollBugLongDesc(NodeList childNodes, BugCommentData longDescData) {
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            Node parentNode = item.getParentNode();
            if (parentNode.getNodeName().equals("commentid")) {
                longDescData.setCommentId(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("who")) {
                longDescData.setWho(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("bug_when")) {
                longDescData.setWhen(item.getNodeValue());
            } else if (parentNode.getNodeName().equals("thetext")) {
                longDescData.setText(item.getNodeValue());
            }

            rollBugLongDesc(item.getChildNodes(), longDescData);
        }
    }

    public static void main(String[] args) {
//        //        test2();
//        String doRequest = getAllIds(MainFrame.CONNECT_DATA);
//        System.out.println("doRequest=" + doRequest);

//        System.out.println(checkUrlAvilable("http://66.239.64.109:8099/bugzilla-3.6.2"));
        
//        System.out.println(getXMLById(MainFrame.CONNECT_DATA, "1658"));
//        System.out.println("-----------------");
//        System.out.println(getXMLByIdWithoutAttachment(MainFrame.CONNECT_DATA, "1658,1212"));
    }

    private static void test2() {
//        Connection con = BugzillaHelpDB.getConnection();
//        SQLTool.closeConnection(con);

        StringBuilder sb = new StringBuilder();
        for (int i = 1; i < 1511; i++) {
            sb.append(i).append(",");
        }

        String byId = getXMLByIdWithoutAttachment(MainFrame.CONNECT_DATA, "2,3,4,5");
//        System.out.println(byId);

        ArrayList<BugDetailData> detailDatas = parseXML(byId);
        for (BugDetailData bugDetailData : detailDatas) {
            System.out.println(bugDetailData);
            System.out.println("");
        }


//        BugDetailData searchById = BugAction.searchById(con, "1506");
//        System.out.println(searchById);


//        ArrayList<BugDetailData> searchAll = BugAction.searchAll(con);
//        for (BugDetailData bugDetailData : searchAll) {
//            System.out.println(bugDetailData);
//            System.out.println("");
//            System.out.println("");
//        }
    }
}
